from django.shortcuts import render
from django.http import HttpResponse, JsonResponse, QueryDict
from utils.auth import login_required, conn_k8s_api
from utils.dateformat import dt_format
from kubernetes import client, config
import time
from k8sManage.models import ClusterInfo, KubeConfig


# Create your views here.

@login_required
def deployment(request):
    return render(request, "workload/deployment.html")


@login_required
def dp_tabledata(request):
    auth_type = request.session.get("auth_type", False)
    namespace_val = request.GET.get("namespace")
    conn_k8s_api(request, auth_type=auth_type)
    apps_api = client.AppsV1Api()
    if request.method == "GET":
        dp_list = []
        try:
            for dp in apps_api.list_namespaced_deployment(namespace_val).items:
                name = dp.metadata.name
                namespace = dp.metadata.namespace
                replicas = dp.spec.replicas
                available_replicas = (0 if dp.status.available_replicas is None else dp.status.available_replicas)
                labels = dp.metadata.labels
                selector = dp.spec.selector.match_labels
                containers = {}
                for c in dp.spec.template.spec.containers:  # 获取pod中所有容器
                    containers[c.name] = c.image
                create_time = dp.metadata.creation_timestamp
                create_time = dt_format(create_time)
                dp = {"name": name, "namespace": namespace, "replicas": replicas,
                      "available_replicas": available_replicas, "labels": labels, "selector": selector,
                      "containers": containers, "create_time": create_time}
                search_key = request.GET.get("key", None)
                if search_key:
                    if search_key in name:  # in 则为模糊查询
                        dp_list.append(dp)
                else:
                    dp_list.append(dp)
            count = len(dp_list)
            page = int(request.GET.get("page"))
            limit = int(request.GET.get("limit"))
            start = (page - 1) * limit
            end = page * limit
            dp_list = dp_list[start:end]
            code = 0
            msg = "deployment获取成功！"
        except Exception as e:
            status = getattr(e, "status")
            if status == 403:
                msg = "无权限！"
            else:
                msg = "查询失败！"
            code = 1
        return JsonResponse({"code": code, "data": dp_list, "msg": msg, "count": count})
    elif request.method == "DELETE":
        del_data = QueryDict(request.body)
        try:
            name = del_data.get('name')
            namespace = del_data.get('namespace')
            apps_api.delete_namespaced_deployment(namespace=namespace, name=name)
            while True:
                name_list = []
                for dp in apps_api.list_namespaced_deployment(namespace).items:
                    name_list.append(dp.metadata.name)
                if name not in name_list:
                    break
                else:
                    time.sleep(1)  # 调用k8s接口删除，需要等待k8s响应
            code = 0
            msg = "删除数据成功！"
        except Exception as e:
            status = getattr(e, "status")
            if status == 403:
                msg = "无权限！"
            else:
                msg = "删除失败！"
            code = 1
        data = {'code': code, 'msg': msg}
        return JsonResponse(data)


@login_required
def dp_details(request):
    auth_type = request.session.get("auth_type", False)
    conn_k8s_api(request, auth_type=auth_type)
    core_api = client.CoreV1Api()
    apps_api = client.AppsV1Api()
    networking_api = client.NetworkingV1Api()
    storage_api = client.StorageV1Api()
    dp_name = request.GET.get("dp_name")
    namespace = request.GET.get("namespace")

    dp_info = {}
    for dp in apps_api.list_namespaced_deployment(namespace=namespace).items:
        if dp_name == dp.metadata.name:
            name = dp.metadata.name
            namespace = dp.metadata.namespace
            replicas = dp.spec.replicas
            available_replicas = (
                0 if dp.status.available_replicas is None else dp.status.available_replicas)  # ready_replicas
            labels = dp.metadata.labels
            selector = dp.spec.selector.match_labels

            # 通过deployment反查对应service
            service = []
            svc_name = None
            for svc in core_api.list_namespaced_service(namespace=namespace).items:
                if svc.spec.selector == selector:
                    svc_name = svc.metadata.name  # 通过该名称筛选ingress
                    type = svc.spec.type
                    cluster_ip = svc.spec.cluster_ip
                    ports = svc.spec.ports

                    data = {"type": type, "cluster_ip": cluster_ip, "ports": ports}
                    service.append(data)

            # service没有创建，ingress也就没有  ingress->service->deployment->pod
            ingress_list = []
            ingress = {"rules": None, "tls": None}
            for ing in networking_api.list_namespaced_ingress(namespace=namespace).items:
                for r in ing.spec.rules:
                    for b in r.http.paths:
                        if b.backend.service.name == svc_name:
                            rules = ing.spec.rules
                            tls = ing.spec.tls
                            ingress = {"rules": rules, "tls": tls}
                            # ingress["rules"] = ing.spec.rules
                            # ingress["tls"] = ing.spec.tls
                            ingress_list.append(ingress)

            containers = []
            for c in dp.spec.template.spec.containers:
                c_name = c.name
                image = c.image
                liveness_probe = c.liveness_probe
                readiness_probe = c.readiness_probe
                resources = c.resources  # 在前端处理
                env = c.env
                ports = c.ports
                volume_mounts = c.volume_mounts
                args = c.args
                command = c.command

                container = {"name": c_name, "image": image, "liveness_probe": liveness_probe,
                             "readiness_probe": readiness_probe,
                             "resources": resources, "env": env, "ports": ports,
                             "volume_mounts": volume_mounts, "args": args, "command": command}
                containers.append(container)

            tolerations = dp.spec.template.spec.tolerations
            rolling_update = dp.spec.strategy.rolling_update
            volumes = []
            if dp.spec.template.spec.volumes is not None:
                for v in dp.spec.template.spec.volumes:  # 返回类似字典格式，不知道为啥不能遍历
                    volume = {}
                    if v.config_map is not None:
                        volume["config_map"] = v.config_map
                    elif v.secret is not None:
                        volume["secret"] = v.secret
                    elif v.empty_dir is not None:
                        volume["empty_dir"] = v.empty_dir
                    elif v.host_path is not None:
                        volume["host_path"] = v.host_path
                    elif v.config_map is not None:
                        volume["downward_api"] = v.downward_api
                    elif v.config_map is not None:
                        volume["glusterfs"] = v.glusterfs
                    elif v.cephfs is not None:
                        volume["cephfs"] = v.cephfs
                    elif v.rbd is not None:
                        volume["rbd"] = v.rbd
                    elif v.persistent_volume_claim is not None:
                        volume["persistent_volume_claim"] = v.persistent_volume_claim
                    else:
                        volume["unknown"] = "unknown"
                    volumes.append(volume)

            rs_number = dp.spec.revision_history_limit
            create_time = dt_format(dp.metadata.creation_timestamp)

            dp_info = {"name": name, "namespace": namespace, "replicas": replicas,
                       "available_replicas": available_replicas, "labels": labels,
                       "selector": selector, "containers": containers, "rs_number": rs_number,
                       "rolling_update": rolling_update, "create_time": create_time, "volumes": volumes,
                       "tolerations": tolerations, "service": service, "ingress": ingress_list}
    return render(request, "workload/deployment_details.html",
                  {'dp_name': dp_name, 'namespace': namespace, 'dp_info': dp_info})


@login_required
def replicaset_api(request):
    auth_type = request.session.get("auth_type", False)
    conn_k8s_api(request, auth_type=auth_type)
    apps_api = client.AppsV1Api()
    if request.method == "GET":
        dp_name = request.GET.get("dp_name")
        namespace = request.GET.get("namespace")
        rs_list = []
        try:
            for rs in apps_api.list_namespaced_replica_set(namespace=namespace).items:
                current_dp_name = rs.metadata.owner_references[0].name
                rs_name = rs.metadata.name
                if dp_name == current_dp_name:
                    namespace = rs.metadata.namespace
                    replicas = rs.status.replicas
                    available_replicas = rs.status.available_replicas
                    ready_replicas = rs.status.ready_replicas
                    revision = rs.metadata.annotations["deployment.kubernetes.io/revision"]
                    create_time = dt_format(rs.metadata.creation_timestamp)

                    containers = {}
                    for c in rs.spec.template.spec.containers:
                        containers[c.name] = c.image

                    rs = {"name": rs_name, "namespace": namespace, "replicas": replicas,
                          "available_replicas": available_replicas, "ready_replicas": ready_replicas,
                          "revision": revision, 'containers': containers, "create_time": create_time}
                    rs_list.append(rs)
            count = len(rs_list)  # 可选，rs默认保存10条，所以不用分页
            code = 0
            msg = "rs数据获取成功！"
        except Exception as e:
            status = getattr(e, "status")
            if status == 403:
                msg = "无权限！"
            else:
                msg = "rs数据获取失败！"
            code = 1
        res = {"code": code, "msg": msg, "count": count, "data": rs_list}
        return JsonResponse(res)
    if request.method == "POST":
        dp_name = request.POST.get("dp_name")  # deployment名称
        namespace = request.POST.get("namespace")
        revision = request.POST.get("revision")  # 需要回滚的版本号
        print(dp_name, namespace, revision)

        '''
        只做参考，官方未提供直接回滚的功能，需要自己通过一些手段实现
        可参考文档： https://github.com/kubernetes-client/python/issues/1232
        '''
        associated_replica_sets = apps_api.list_namespaced_replica_set(
            namespace=namespace,
        )

        revision_ordered_replica_sets = sorted(
            associated_replica_sets.items,
            key=lambda e: e.metadata.annotations['deployment.kubernetes.io/revision'],
            reverse=True
        )

        idx = 0
        for i in revision_ordered_replica_sets:
            idx += 1
            for k, v in i.metadata.annotations.items():
                if (k == "deployment.kubernetes.io/revision" and v == revision):
                    break
        rollback_replica_set = (
            revision_ordered_replica_sets[idx - 1]
        )
        patch = [
            {
                'op': 'replace',
                'path': '/spec/template',
                'value': rollback_replica_set.spec.template
            },
            {
                'op': 'replace',
                'path': '/metadata/annotations',
                'value': {
                    'deployment.kubernetes.io/revision': revision,
                }
            }
        ]

        try:
            apps_api.patch_namespaced_deployment(name=dp_name, namespace=namespace, body=patch)
            code = 0
            msg = "回滚成功！"
        except Exception as e:
            print(e)
            status = getattr(e, "status")
            if status == 403:
                msg = "你没有回滚权限！"
            else:
                msg = "回滚失败！"
            code = 1
        res = {"code": code, "msg": msg}
        return JsonResponse(res)


@login_required
def statefulset(request):
    return render(request, "workload/statefulset.html")


@login_required
def sts_tabledata(request):
    auth_type = request.session.get("auth_type", False)
    namespace_val = request.GET.get("namespace")
    conn_k8s_api(request, auth_type=auth_type)
    apps_api = client.AppsV1Api()
    if request.method == "GET":
        sts_list = []
        try:
            for sts in apps_api.list_namespaced_stateful_set(namespace_val).items:
                name = sts.metadata.name
                namespace = sts.metadata.namespace
                labels = sts.metadata.labels
                selector = sts.spec.selector.match_labels
                replicas = sts.spec.replicas
                ready_replicas = ("0" if sts.status.ready_replicas is None else sts.status.ready_replicas)
                # current_replicas = sts.status.current_replicas
                service_name = sts.spec.service_name
                containers = {}
                for c in sts.spec.template.spec.containers:
                    containers[c.name] = c.image
                create_time = sts.metadata.creation_timestamp
                create_time = dt_format(create_time)
                sts = {"name": name, "namespace": namespace, "labels": labels, "replicas": replicas,
                       "ready_replicas": ready_replicas, "service_name": service_name,
                       "selector": selector, "containers": containers, "create_time": create_time}
                search_key = request.GET.get("key", None)
                if search_key:
                    if search_key in name:  # in 则为模糊查询
                        sts_list.append(sts)
                else:
                    sts_list.append(sts)
            count = len(sts_list)
            page = int(request.GET.get("page"))
            limit = int(request.GET.get("limit"))
            start = (page - 1) * limit
            end = page * limit
            sts_list = sts_list[start:end]
            code = 0
            msg = "statefulset获取成功！"
        except Exception as e:
            status = getattr(e, "status")
            if status == 403:
                msg = "无权限！"
            else:
                msg = "查询失败！"
            code = 1
        return JsonResponse({"code": code, "data": sts_list, "msg": msg, "count": count})
    elif request.method == "DELETE":
        del_data = QueryDict(request.body)
        try:
            name = del_data.get('name')
            namespace = del_data.get('namespace')
            apps_api.delete_namespaced_stateful_set(namespace=namespace, name=name)
            while True:
                name_list = []
                for sts in apps_api.list_namespaced_stateful_set(namespace).items:
                    name_list.append(sts.metadata.name)
                if name not in name_list:
                    break
                else:
                    time.sleep(1)  # 调用k8s接口删除，需要等待k8s响应
            code = 0
            msg = "删除数据成功！"
        except Exception as e:
            status = getattr(e, "status")
            if status == 403:
                msg = "无权限！"
            else:
                msg = "删除失败！"
            code = 1
        data = {'code': code, 'msg': msg}
        return JsonResponse(data)


@login_required
def daemonset(request):
    return render(request, "workload/daemonset.html")


@login_required
def ds_tabledata(request):
    auth_type = request.session.get("auth_type", False)
    namespace_val = request.GET.get("namespace")
    conn_k8s_api(request, auth_type=auth_type)
    apps_api = client.AppsV1Api()
    if request.method == "GET":
        ds_list = []
        try:
            for ds in apps_api.list_namespaced_daemon_set(namespace_val).items:
                name = ds.metadata.name
                namespace = ds.metadata.namespace
                desired_number = ds.status.desired_number_scheduled
                available_number = ds.status.number_available
                labels = ds.metadata.labels
                selector = ds.spec.selector.match_labels
                containers = {}
                for c in ds.spec.template.spec.containers:
                    containers[c.name] = c.image
                create_time = ds.metadata.creation_timestamp
                create_time = dt_format(create_time)
                ds = {"name": name, "namespace": namespace, "labels": labels, "desired_number": desired_number,
                      "available_number": available_number,
                      "selector": selector, "containers": containers, "create_time": create_time}
                search_key = request.GET.get("key", None)
                if search_key:
                    if search_key in name:  # in 则为模糊查询
                        ds_list.append(ds)
                else:
                    ds_list.append(ds)
            count = len(ds_list)
            page = int(request.GET.get("page"))
            limit = int(request.GET.get("limit"))
            start = (page - 1) * limit
            end = page * limit
            ds_list = ds_list[start:end]
            code = 0
            msg = "daemonset获取成功！"
        except Exception as e:
            status = getattr(e, "status")
            if status == 403:
                msg = "无权限！"
            else:
                msg = "查询失败！"
            code = 1
        return JsonResponse({"code": code, "data": ds_list, "msg": msg, "count": count})
    elif request.method == "DELETE":
        del_data = QueryDict(request.body)
        try:
            name = del_data.get('name')
            namespace = del_data.get('namespace')
            apps_api.delete_namespaced_daemon_set(namespace=namespace, name=name)
            while True:
                name_list = []
                for ds in apps_api.list_namespaced_daemon_set(namespace).items:
                    name_list.append(ds.metadata.name)
                if name not in name_list:
                    break
                else:
                    time.sleep(1)  # 调用k8s接口删除，需要等待k8s响应
            code = 0
            msg = "删除数据成功！"
        except Exception as e:
            status = getattr(e, "status")
            if status == 403:
                msg = "无权限！"
            else:
                msg = "删除失败！"
            code = 1
        data = {'code': code, 'msg': msg}
        return JsonResponse(data)


@login_required
def pods(request):
    return render(request, "workload/pods.html")


@login_required
def pod_tabledata(request):
    auth_type = request.session.get("auth_type", False)
    namespace_val = request.GET.get("namespace")
    conn_k8s_api(request, auth_type=auth_type)
    core_api = client.CoreV1Api()
    if request.method == "GET":
        po_list = []
        try:
            for po in core_api.list_namespaced_pod(namespace_val).items:
                name = po.metadata.name
                namespace = po.metadata.namespace
                labels = po.metadata.labels
                pod_ip = po.status.pod_ip

                containers = []  # [{},{},{}]
                status = "None"
                # 为None说明Pod没有创建（不能调度或者正在下载镜像）
                if po.status.container_statuses is None:
                    status = po.status.conditions[-1].reason
                else:
                    for c in po.status.container_statuses:
                        c_name = c.name
                        c_image = c.image
                        # 获取重启次数
                        restart_count = c.restart_count
                        # 获取容器状态
                        c_status = "None"
                        if c.ready is True:
                            c_status = "Running"
                        elif c.ready is False:
                            if c.state.waiting is not None:
                                c_status = c.state.waiting.reason
                            elif c.state.terminated is not None:
                                c_status = c.state.terminated.reason
                            elif c.state.last_state.terminated is not None:
                                c_status = c.last_state.terminated.reason

                        c = {'c_name': c_name, 'c_image': c_image, 'restart_count': restart_count, 'c_status': c_status}
                        containers.append(c)
                create_time = po.metadata.creation_timestamp
                create_time = dt_format(create_time)
                po = {"name": name, "namespace": namespace, "pod_ip": pod_ip,
                      "labels": labels, "containers": containers, "status": status,
                      "create_time": create_time}
                search_key = request.GET.get("key", None)
                if search_key:
                    if search_key in name:  # in 则为模糊查询
                        po_list.append(po)
                else:
                    po_list.append(po)
            count = len(po_list)
            page = int(request.GET.get("page"))
            limit = int(request.GET.get("limit"))
            start = (page - 1) * limit
            end = page * limit
            po_list = po_list[start:end]
            code = 0
            msg = "pod获取成功！"
        except Exception as e:
            status = getattr(e, "status")
            if status == 403:
                msg = "无权限！"
            else:
                msg = "查询失败！"
            code = 1
        return JsonResponse({"code": code, "data": po_list, "msg": msg, "count": count})
    elif request.method == "DELETE":
        del_data = QueryDict(request.body)
        try:
            name = del_data.get('name')
            namespace = del_data.get('namespace')
            core_api.delete_namespaced_pod(namespace=namespace, name=name)
            while True:
                name_list = []
                for po in core_api.list_namespaced_pod(namespace).items:
                    name_list.append(po.metadata.name)
                if name not in name_list:
                    break
                else:
                    time.sleep(1)  # 调用k8s接口删除，需要等待k8s响应
            code = 0
            msg = "删除数据成功！"
        except Exception as e:
            status = getattr(e, "status")
            print(status)
            if status == 403:
                msg = "无权限！"
            else:
                msg = "删除失败！"
            code = 1
        data = {'code': code, 'msg': msg}
        return JsonResponse(data)


@login_required
def web_terminal(request):
    namespace = request.GET.get("namespace")
    pod_name = request.GET.get("pod_name")
    containers = request.GET.get("containers").split(',')

    # 传参用于k8s集群连接的参数 用于django channel连接k8s
    auth_type = request.session.get("auth_type", False)
    token = request.session.get("token", False)
    cluster_name = request.session.get("cluster_name", False)
    cluster_host = ClusterInfo.objects.get(cluster_name=cluster_name).cluster_address


    data = {'namespace': namespace, 'pod_name': pod_name, 'containers': containers, 'auth_type': auth_type,
            'token': token, 'cluster_host': cluster_host}
    return render(request, 'workload/pod_terminal.html', {'data': data})

@login_required
def log_terminal(request):
    namespace = request.GET.get("namespace")
    pod_name = request.GET.get("pod_name")
    containers = request.GET.get("containers").split(',')

    # 传参用于k8s集群连接的参数 用于django channel连接k8s
    auth_type = request.session.get("auth_type", False)
    token = request.session.get("token", False)
    cluster_name = request.session.get("cluster_name", False)
    cluster_host = ClusterInfo.objects.get(cluster_name=cluster_name).cluster_address

    data = {'namespace': namespace, 'pod_name': pod_name, 'containers': containers, 'auth_type': auth_type,
            'token': token, 'cluster_host': cluster_host}
    return render(request, 'workload/pod_log.html', {'data': data})